package com.power.leopard.util;

import java.util.concurrent.ConcurrentHashMap;

import com.power.leopard.ConfigManagerLoader;
import com.power.leopard.config.ConfigManager;
import com.power.leopard.constants.Constants;
import com.power.leopard.remote.provider.domain.InvocationSerializable;


public class TimelineManager {

	public enum Phase {
		Start/* 0 */, ClientEncoded/* 1 */, ClientSent/* 2 */, ClientException/* 3 */, ServerReceived/* 4 */, ServerDecoded/* 5 */, ServerException/* 6 */, BusinessStart/* 7 */, BusinessEnd/* 8 */, ServerEncoded/* 9 */, ServerSent/* 10 */, ClientReceived/* 11 */, ClientDecoded/* 12 */, End/* 13 */
	};
	
	private static volatile ConcurrentHashMap<String, Timeline> sequenceMap = new ConcurrentHashMap<String, Timeline>();

	private static boolean enabled;
	private static long abnormalThreshold;
	private static long legacyThreshold;
	private static long lastRemoveTime;
	private static String localIp;
	
	static {
		ConfigManager config = ConfigManagerLoader.getConfigManager();
//		config.registerConfigChangeListener(new InnerConfigChangeListener());
		enabled = config.getBooleanValue("pigeon.timeline.log.enabled", true);
//		abnormalThreshold = config.getLongValue("pigeon.timeline.abnormal.threshold", 50);
//		legacyThreshold = config.getLongValue("pigeon.timeline.legacy.threshold", 60000);
//		localIp = config.getLocalIp();
	}

	
	public static class Timeline {
		private long[] timeline;

		public Timeline() {
			timeline = new long[Phase.values().length];
		}

		public void time(Phase phase) {
			timeline[phase.ordinal()] = System.currentTimeMillis();
		}

		public void time(Phase phase, long timestamp) {
			timeline[phase.ordinal()] = timestamp;
		}

		public long[] getTimeline() {
			return timeline;
		}

		public String toString() {
			StringBuilder sb = new StringBuilder();
			long startTime = 0;
			for (int i = 0; i < timeline.length; i++) {
				if (timeline[i] == 0)
					continue;
				if (startTime == 0) {
					startTime = timeline[i];
					sb.append(i).append(':').append(startTime);
				} else {
					int delta = (int) (timeline[i] - startTime);
					sb.append(',').append(i).append(":+").append(delta);
				}
			}
			return sb.toString();
		}

	}
	
	private static boolean shouldTime(InvocationSerializable message) {
		return enabled && message.getMessageType() != Constants.MESSAGE_TYPE_HEART
				&& message.getMessageType() != Constants.MESSAGE_TYPE_HEALTHCHECK;
	}
	
	private static Timeline _getTimeline(String key) {
		Timeline tl = sequenceMap.get(key);
		if (tl == null) {
			tl = new Timeline();
			Timeline _tl = sequenceMap.putIfAbsent(key, tl);
			if (_tl != null) {
				tl = _tl;
			}
		}
		return tl;
	}
	
	public static void time(InvocationSerializable message, String ip, Phase phase) {
		if (shouldTime(message)) {
			Timeline tl = _getTimeline(ip + message.getSequence());
			if (phase.ordinal() == 2 && tl.getTimeline()[0] == 0) {
				sequenceMap.remove(ip + message.getSequence());
			} else {
				tl.time(phase);
			}
		}
	}
	
	public static String getRemoteIp() {
		return (String) ContextUtils.getLocalContext("CLIENT_IP");
	}
	
	public static boolean isEnabled() {
		return enabled;
	}
}
